/**
 * AbstractIdentifier
 * abstract:抽象
 * abstract修饰的方法,叫做抽象方法,父类不实现,只是为了让子类覆写,用来实现多态
 * 
 * 抽象类无法被实例化
 * 因为抽象类的设计就是为了被继承,抽象类的子类必须实现抽象类的抽象方法,否则会编译错误,这样的抽象类更像是定义了一种规范
 * 
 */
public class AbstractIdentifier {

     public static void main(String[] args) {
         Student xiaoli = new Student();
         xiaoli.run();
     }
}
// 把一个方法声明为abstract，表示它是一个抽象方法，本身没有实现任何方法语句。因为这个抽象方法本身是无法执行的，所以，Person类也无法被实例化。编译器会告诉我们，无法编译Person类，因为它包含抽象方法。必须把Person类本身也声明为abstract，才能正确编译它：
// 抽象方法只能由抽象类定义:
abstract class AbstractPerson {
    public abstract void run();
}

class Student {
    public void run(){
        System.out.println("I run");
    }
}

// 面向抽象编程
/**
 * 当我们定义了抽象类Person，以及具体的Student、Teacher子类的时候，我们可以通过抽象类Person类型去引用具体的子类的实例：

Person s = new Student();
Person t = new Teacher();
这种引用抽象类的好处在于，我们对其进行方法调用，并不关心Person类型变量的具体子类型：

// 不关心Person变量的具体子类型:
s.run();
t.run();
同样的代码，如果引用的是一个新的子类，我们仍然不关心具体类型：

// 同样不关心新的子类是如何实现run()方法的：
Person e = new Employee();
e.run();
这种尽量引用高层类型，避免引用实际子类型的方式，称之为面向抽象编程。

面向抽象编程的本质就是：

上层代码只定义规范（例如：abstract class Person）；

不需要子类就可以实现业务逻辑（正常编译）；

具体的业务逻辑由不同的子类实现，调用者并不关心。
 */
